package j.util.jdbc;

import j.framework.qmd.core.DataType;
import j.framework.qmd.core.QueryFieldMetadata;
import j.data.ActionResult;
import j.data.PagedData;
import j.util.New;
import j.util.StringUtils;
import j.util.TwoTuple;
import j.util.json.JsonUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * User: jason
 * Date: 13-4-19 上午9:52
 */
public abstract class JdbcTemplate {
    public static final int DEFAULT_PAGE_SIZE = 10;

    /**
     * 把原生的sql语句放到%1$s的位置,第一个参数为:起始值( startRow = (pageIndex-1)*pageSize+1;),
     * 第二个参数为:结束值(endRow = pageIndex * pageSize)
     */
    public static final String ORACLE_PAGING_TEMPLATE = "SELECT * FROM (" +
            "SELECT ROWNUM rn,TBL_ORACLE_PAGINATION_.* FROM(" +
            "	%1$s) TBL_ORACLE_PAGINATION_ WHERE ROWNUM<=?) WHERE rn>=?";

    /**
     * MySql的分页模板
     * %1$s => 查询语句
     * %2$d => offset 记录行的偏移量，以0为基数
     * %3$d => rows 页大小
     */
    public static final String MYSQL_PAGING_TEMPLATE = "%1$s LIMIT ?,?";
    //select * from tbl_name order by id OFFSET start_row ROW FETCH NEXT page_size ROWS ONLY;
    public static final String MSSQL_PAGING_TEMPLATE = "%1$s OFFSET ? ROW FETCH NEXT ? ROWS ONLY";

    protected static Log log = LogFactory.getLog("db");
    protected DataSource dataSource;

    public JdbcTemplate(){}

    public JdbcTemplate(DataSource ds){
        dataSource = ds;
    }

    public void setDataSource(DataSource ds){
        this.dataSource = ds;
    }
    public DataSource getDataSource(){
        return this.dataSource;
    }

    public void close(){}

    public void commit(){}

    public void rollback(){}

    /**
     * 执行单数据查询，若数据库中有多条符合记录，则仅获取第一条（根据sql语句的排序结果）
     * @param sql
     * @param rowMapper
     * @param args
     * @param <T>
     * @return
     */
    public abstract <T> T queryForDomain(String sql,RowMapper<T> rowMapper,Object...args);

    public abstract void queryForDomain(String sql, ResultSetHandler resultSetHandler, Object... args);

    /**
     * 查询单记录集,以map形式返回,key即为字段名字
     * @param sql
     * @param args
     * @return
     */
    public abstract Map<String,Object> queryForMap(String sql,Object...args);

    /**
     * 查询单记录集，以map形式返回，key为字段名字，sql语句为namedsql
     * @param namedSql namedSql形式的sql，如：select * from table_a where id=:id
     * @param queryParams map形式参数
     * @return
     */
    public Map<String, Object> queryForMapByNamedSql(String namedSql, Map<String, Object> queryParams) {
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql,queryParams);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return queryForMap(tt.first,tt.second.toArray());
    }

    /**
     * 查询单记录集，以map形式返回，key为字段名字，sql语句为namedsql
     * @param namedSql namedSql形式的sql，如：select * from table_a where id=:id
     * @param jsonParams json形式参数
     * @return
     */
    public Map<String, Object> queryForMapByNamedSql(String namedSql, String jsonParams) {
        return queryForMap(namedSql, JsonUtils.parseMap(jsonParams));
    }

    /**
     * 将结果集封装在List<Map<String,Object>>中
     * @param sql
     * @param args
     * @return
     */
    public abstract List<Map<String,Object>> queryForListMap(String sql,Object...args);

    /**
     * 以namedsql语句查询记录集，记录集封装在ListMap中
     * @param namedSql
     * @param queryParams
     * @return
     */
    public List<Map<String,Object>> queryForListMapByNamedSql(String namedSql,Map<String,Object> queryParams){
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql,queryParams);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return queryForListMap(tt.first,tt.second.toArray());
    }

    /**
     * 以json作为参数查询ListMap形式的结果集
     * @param namedSql
     * @param jsonParams
     * @return
     */
    public List<Map<String,Object>> queryForListMapByNamedSql(String namedSql,String jsonParams){
        return queryForListMapByNamedSql(namedSql, JsonUtils.parseMap(jsonParams));
    }

    /**
     *将结果集封装在List<Map<String,Object>>中,key为tableName_fieldName
     * @param sql
     * @param args
     * @return
     */
    public List<Map<String,Object>> queryForListMapWithFullKey(String sql,String footerSql,Collection<QueryFieldMetadata> fieldMetadatas,List<Map<String,Object>> listFooters,Object...args){
        log.debug(String.format("在共享连接中执行数据集查询(List<Map>)sql语句：%s，参数：%s.",sql,getArgsInfo(args)));
        List<Map<String,Object>> list = New.list();
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try{
            conn = dataSource.getConnection();
            stmt = conn.prepareStatement(sql);
            JdbcUtils.setStatementArguments(stmt, args);
            rs = stmt.executeQuery();
            retriveMapDataFromResultSet(rs,fieldMetadatas,list);
            rs.close();stmt.close();
            //获取footer
            if(StringUtils.isNotEmpty(footerSql)){
                log.debug("获取footer:"+footerSql);
                stmt = conn.prepareStatement(footerSql);
                JdbcUtils.setStatementArguments(stmt,args);
                rs = stmt.executeQuery();
                loadMapDataFromResult(rs, listFooters);
            }
        }catch(SQLException e){
            log.error(String.format("在共享连接中执行数据集查询(List<Map>)sql语句：%s时出现异常：%s.", sql, e.getMessage()));
            throw new RabbitJdbcException(String.format("JdbcTemplate.queryForListMap在共享连接中执行数据集(List<Map>)查询时出现异常：%s.",e.getMessage()));
        }finally{
            JdbcUtils.free(conn, stmt, rs);
        }
        return list;
    }
    public PagedData<List<Map<String,Object>>> queryForPagingListMapWithFullKey(String sql,String footerSql,
                                                                                Collection<QueryFieldMetadata> fieldMetadatas,
                                                                                int pageIndex,int pageSize,List<Map<String,Object>> listFooters,Object...args){
        List<Map<String,Object>> list = New.list();
                log.debug(String.format("在共享连接中执行数据集查询(List<Map>)sql语句：%s，参数：%s.", sql, getArgsInfo(args)));
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        int totalList = 0;
        try{
            if(pageIndex<=0){
                pageIndex = 1;
            }
            if(pageSize<=0){
                pageSize = DEFAULT_PAGE_SIZE;
            }
            Object[] _args = new Object[args.length+2];
            int i;
            for(i=0;i<args.length;i++){
                _args[i] = args[i];
            }
            String _sql = null;
            DatabaseType dbType = JdbcPlatform.getDatabaseType(dataSource);
            if(dbType.equals(DatabaseType.MYSQL)){
                //mysql数据库
                _args[i++] = (pageIndex-1)*pageSize;
                _args[i] = pageSize;
                _sql = String.format(JdbcTemplate.MYSQL_PAGING_TEMPLATE,sql);
            }else if(dbType.equals(DatabaseType.MSSQL)){
                _sql = String.format(JdbcTemplate.MSSQL_PAGING_TEMPLATE,sql);
                _args[i++] = (pageIndex-1)*pageSize;
                _args[i] = pageSize;
            }else if(dbType.equals(DatabaseType.ORACLE)){
                _sql = String.format(JdbcTemplate.ORACLE_PAGING_TEMPLATE,sql);
                _args[i++] = (pageIndex-1)*pageSize+1;
                _args[i] = pageSize;
            }
            conn = dataSource.getConnection();
            //先计算总记录数
            boolean isComplex = sql.contains("@@");
            stmt = conn.prepareStatement(JdbcUtils.formatSqlToCount(sql, isComplex));
            JdbcUtils.setStatementArguments(stmt, args);
            rs = stmt.executeQuery();
            if(rs.next()){
                totalList = rs.getInt(1);
            }
            rs.close();stmt.close();
            if(isComplex){
                _sql = _sql.replaceFirst("@@","");
            }
            stmt = conn.prepareStatement(_sql);
            JdbcUtils.setStatementArguments(stmt, _args);
            rs = stmt.executeQuery();
            retriveMapDataFromResultSet(rs,fieldMetadatas,list);
            rs.close();stmt.close();
            //获取footer
            if(StringUtils.isNotEmpty(footerSql)) {
                stmt = conn.prepareStatement(footerSql);
                JdbcUtils.setStatementArguments(stmt,args);
                rs = stmt.executeQuery();
                loadMapDataFromResult(rs, listFooters);
            }

        } catch (SQLException e){
            log.error(String.format("在共享连接中执行数据集查询(List<Map>)sql语句：%s时出现异常：%s.", sql, e.getMessage()));
            throw new RabbitJdbcException(String.format("JdbcTemplate.queryForListMap在共享连接中执行数据集(List<Map>)查询时出现异常：%s.",e.getMessage()));
        }finally{
            JdbcUtils.free(conn, stmt, rs);
        }
        return new PagedData<List<Map<String,Object>>>(pageIndex,pageSize,totalList,list);
    }

    private static void loadMapDataFromResult(ResultSet rs,List<Map<String,Object>> list)throws SQLException{
        Map<String,Object> map;
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();
        while(rs.next()) {
            map = New.map(columnCount);
            for (int i = 1; i <= columnCount; i++) {
                String key = rsmd.getColumnName(i);
                Object obj = JdbcUtils.getResultSetValue(rs, i);
                map.put(key, obj);
            }
            list.add(map);
        }
    }

    private static void retriveMapDataFromResultSet(
            ResultSet rs,Collection<QueryFieldMetadata> fieldMetadatas,
            List<Map<String,Object>> list)throws SQLException{
        Map<String,Object> map;
        String key;
        Object objV;
        BigDecimal bd;
        DataType dt ;
        while(rs.next()){
                /*rsmd = rs.getMetaData();
                if(columnCount==0){
                    columnCount = rsmd.getColumnCount();
                }
                map = New.map();
                for (i = 1; i <= columnCount; i++) {
                    //key = rsmd.getTableName(i) +"_" + rsmd.getColumnName(i);
                    key = rsmd.getColumnName(i);
                    objV = JdbcUtils.getResultSetValue(rs, i);
                    map.put(key, objV);
                }*/
            map = New.map();
            for(QueryFieldMetadata qfmd : fieldMetadatas){
                key = qfmd.getFieldName();
                dt = qfmd.getDataType();

                if(dt.equals(DataType.STRING)){
                    map.put(key,rs.getString(key));
                }else if(dt.equals(DataType.INTEGER)){
                    objV = rs.getObject(key);
                    if(objV!=null){
                        if(objV instanceof Integer){
                            map.put(key,objV);
                        }else if(objV instanceof Short){
                            map.put(key,((Short)objV).intValue());
                        }else{
                            map.put(key,objV);
                        }
                    }else{
                        map.put(key,null);
                    }
                }else if(dt.equals(DataType.LONG)){
                    objV = rs.getObject(key);
                   // bd = (BigDecimal)objV;
                    if(objV == null){
                        map.put(key,null);
                    }else{
                        if(objV instanceof BigDecimal){
                            bd = (BigDecimal)objV;
                            map.put(key,bd.longValue());
                        }else{
                            map.put(key,objV);
                        }
                    }
                }else if(dt.equals(DataType.FLOAT)){
                    //浮点类型
                        bd = rs.getBigDecimal(key);
                        if(null!=bd){
                            map.put(key,bd.floatValue());
                        }else{
                            map.put(key,null);
                        }
                }else if(dt.equals(DataType.DOUBLE)){
                    //浮点类型
                        bd = rs.getBigDecimal(key);
                        if(null!=bd){
                            map.put(key,bd.doubleValue());
                        }else{
                            map.put(key,null);
                        }
                }else if(dt.equals(DataType.DATE)
                        || dt.equals(DataType.DATETIME)){
                    Timestamp ts = rs.getTimestamp(key);
                    if(ts == null){
                        map.put(key,null);
                    }else{
                        map.put(key,new java.util.Date(ts.getTime()));
                    }
                }else if(dt.equals(DataType.BOOLEAN)){
                    objV = rs.getObject(key);
                    if(objV != null){
                        if(objV instanceof Integer){
                            map.put(key,(Integer)objV>0);
                        }else if(objV instanceof Short){
                            map.put(key,(Short)objV>0);
                        }else if(objV instanceof String){
                            map.put(key,((String)objV).trim().equals("1"));
                        }else{
                            map.put(key,false);
                        }
                    }else{
                        map.put(key,false);
                    }
                }else if(dt.equals(DataType.TIME)){
                    map.put(key,rs.getTime(key));
                }
            }
            list.add(map);
        }
    }

    /**
     * 发页形式查询，以List<Map封装数据
     * @param sql
     * @param pageIndex
     * @param pageSize
     * @param args
     * @return
     */
    public abstract PagedData<List<Map<String,Object>>> queryForPaging(String sql,int pageIndex,int pageSize,Object...args);

    public abstract  <T> PagedData<List<T>> queryForPaging(String sql,RowMapper<T> rowMapper,
                                                           int pageIndex,int pageSize,Object... args);

    /**
     * 分页查询
     * @param namedSql
     * @param rowMapper
     * @param pageIndex
     * @param pageSize
     * @param queryParams
     * @param <T>
     * @return
     */
    public <T> PagedData<List<T>> queryForPagingByNamedSql(String namedSql,RowMapper<T> rowMapper,
                                                           int pageIndex,int pageSize,Map<String,Object> queryParams){
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql,queryParams);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return queryForPaging(tt.first, rowMapper, pageIndex, pageSize, tt.second.toArray());
    }

    /**
     * 分页查询，参数为json形式
     * @param namedSql
     * @param rowMapper
     * @param pageIndex
     * @param pageSize
     * @param jsonParams
     * @param <T>
     * @return
     */
    public <T> PagedData<List<T>> queryForPagingByNamedSql(String namedSql,RowMapper<T> rowMapper,
                                                    int pageIndex,int pageSize,String jsonParams){
        return queryForPagingByNamedSql(namedSql, rowMapper, pageIndex, pageSize, JsonUtils.parseMap(jsonParams));
    }

    /**
     * 查询记录集，只要不出现异常，数据库中没有符合条件的数据时，将返回空集合
     * @param sql
     * @param rowMapper
     * @param args
     * @param <T>
     * @return
     */
    public abstract  <T> List<T> queryForList(String sql,RowMapper<T> rowMapper,Object...args);

    public <T> List<T> queryForListByNamedSql(String namedSql,RowMapper<T> rowMapper,Map<String,Object> namedParameters){
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql, namedParameters);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return queryForList(tt.first, rowMapper, tt.second.toArray());
    }

    /**
     * 以json参数查询不分页列表
     * @param namedSql
     * @param rowMapper
     * @param jsonParameters
     * @param <T>
     * @return
     */
    public <T> List<T> queryForListByNamedSql(String namedSql,RowMapper<T> rowMapper,String jsonParameters){
        return queryForListByNamedSql(namedSql, rowMapper, JsonUtils.parseMap(jsonParameters));
    }

    public abstract void queryForList(String sql,ResultSetHandler resultSetHandler,Object...args);

    public ActionResult executeWithTransaction(TransactionHandler transactionHandler){
        log.debug(String.format("执行用户自定义的事务[%s].",transactionHandler));
        final ActionResult ar = ActionResult.New();
        Connection conn = null;
        PreparedStatement stmt = null;
        try{
            conn = dataSource.getConnection();
            conn.setAutoCommit(false);
            transactionHandler.doTransaction(conn, ar);
            conn.commit();
            log.debug(String.format("执行用户自定义的事务[%s]成功并成功提交.",transactionHandler));
        }catch(SQLException e){
            try {
                if(null!=conn){
                    conn.rollback();
                }
            } catch (SQLException e1) {
                ar.add(String.format("回滚事务时失败,异常:%s.",e1.getMessage()));
                log.error(String.format("执行用户自定义的事务[%s]失败并在回滚时又失败，异常信息：%s.",transactionHandler,e1.getMessage()));
                throw new RabbitJdbcException(String.format("JdbcTemplate.queryForList(处理事务)回滚整条时出现异常：%s.",e1.getMessage()));
            }
            ar.add(String.format("事务执行失败并成功回滚,异常:%s.",e.getMessage()));
            log.error(String.format("执行用户自定义的事务[%s]失败并成功回滚，异常信息：%s.",transactionHandler,e.getMessage()));
            throw new RabbitJdbcException(String.format("JdbcTemplate.executeWithTranstion(处理事务)执行数据查询时出现异常：%s.",e.getMessage()));
        }finally{
            JdbcUtils.free(conn, stmt);
        }
        return ar;
    }

    public abstract int queryForInt(String sql,Object...args);
    public int queryForIntByNamedSql(String namedSql,Map<String,Object> namedParameters){
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql, namedParameters);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return queryForInt(tt.first, tt.second.toArray());
    }
    public int queryForIntByNamedSql(String namedSql,String jsonParameters){
        return queryForIntByNamedSql(namedSql, JsonUtils.parseMap(jsonParameters));
    }

    public abstract Object queryForObject(String sql,Object...args);
    public Object queryForObjectByNamedSql(String namedSql,Map<String,Object> namedParameters){
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql, namedParameters);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return queryForObject(tt.first, tt.second.toArray());
    }
    public Object queryForObjectByNamedSql(String namedSql,String jsonParameters){
        return queryForObjectByNamedSql(namedSql, JsonUtils.parseMap(jsonParameters));
    }

    /**
     * 执行操作语句
     * 返回本次操作所影响的行数
     * @param sql
     * @param args
     */
    public abstract int execute(String sql,Object...args);
    public int executeByNamedSql(String namedSql, Map<String, Object> namedParameters) {
        TwoTuple<String,List<Object>> tt = JdbcUtils.parseNamedSql(namedSql, namedParameters);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getListInfo(tt.second)));
        return execute(tt.first, tt.second.toArray());
    }

    public int executeByNamedSql(String namedSql, String jsonParameters) {
        return executeByNamedSql(namedSql, JsonUtils.parseMap(jsonParameters));
    }

    /**
     * 批量执行操作语句
     * @param sql
     * @param argsList
     */
    public abstract int[] executeBatch(String sql,List<Object[]> argsList);
    public int[] executeBatchByNamedSql(String namedSql, List<Map<String,Object>> namedParameters) {
        TwoTuple<String,List<Object[]>> tt = JdbcUtils.parseNamedSql(namedSql, namedParameters);
        log.debug(String.format("解析NamedSql[%s]为JdbcSql[%s]，参数：%s",namedSql,tt.first,getArgsInfo(tt.second)));
        return executeBatch(tt.first, tt.second);
    }

    public int[] executeBatchByNamedSql(String namedSql, String jsonParameters) {
        return executeBatchByNamedSql(namedSql, JsonUtils.parseListMap(jsonParameters));
    }

    protected static String getArgsInfo(Object...args){
        if(null == args || args.length==0){
            return "【No Args】";
        }
        StringBuilder s = new StringBuilder("[");
        for(Object obj : args){
            s.append(obj).append(",");
        }
        s.deleteCharAt(s.length()-1);
        s.append("]");
        return s.toString();
    }
    protected static String getListInfo(List<Object> list){
        if(null == list || list.size()==0){
            return "【No Args】";
        }
        StringBuilder s = new StringBuilder("[");
        for(Object obj : list){
            s.append(obj).append(",");
        }
        s.deleteCharAt(s.length()-1);
        s.append("]");
        return s.toString();
    }

    protected static String getListArgsInfo(List<Object[]> argsList){
        if(null == argsList || argsList.size()==0){
            return "【No Args】";
        }
        StringBuilder s = new StringBuilder("{");
        for(Object[] args : argsList){
            s.append("[");
            for(Object obj : args){
                s.append(obj).append(",");
            }
            s.deleteCharAt(s.length()-1);
            s.append("]");
        }
        s.deleteCharAt(s.length()-1);
        s.append("}");
        return s.toString();
    }

    public abstract int executeInsert(String tableName,Map<String,Object> columnValuesMap);

    /**
     * 将map中的数据update到指定的表中,whereSql不必写where关键词
     * @param tableName
     * @param updatedColumnValuesMap
     * @param whereSql
     * @param whereArgs
     * @return
     */
    public abstract int executeUpdate(String tableName,Map<String,Object> updatedColumnValuesMap,String whereSql,Object...whereArgs);

    public <T> T execute(ConnectionCallback<T> callback){
        Connection conn = null;
        try{
            conn = dataSource.getConnection();
            return callback.doInConnection(conn);
        }catch(SQLException e){
            throw new RabbitJdbcException(String.format("JdbcTemplate.execute(with ConnectionCallback)执行自定义操作时异常：%s.",e.getMessage()));
        }finally{
            JdbcUtils.free(conn, null);
        }
    }

    /**
     * 将一个实体对象保存之数据库中
     * 返回代码：-1:数据库中已有重复的（根据pk/uk来判断是否有重复）；0：失败；>0：受影响的行数，在这里应该是1
     * @param object
     * @return
     */
    public abstract int insert(Object object);

    /**
     * 将一个实体对象保存之数据库中，且该数据库表应该有一个且仅有一个字段是自增
     * @param object
     * @return
     */
    public abstract Number insertAndReturnKey(Object object);

    /**
     * 批量插入
     * @param objects
     * @return
     */
    public abstract int[] insertBatch(Class<?> clazz,List<?> objects);

    /**
     * 从数据库中删除一个实体
     * @param t
     * @return
     */
    public abstract  <T> int delete(T t);

    /**
     * 批量删除
     * @param list
     * @return
     */
    public abstract <T> int[] deleteBatch(List<T> list);

    /**
     * 参数以map形式指定,key为实体属性的名字，而非数据库字段名称
     * @param clazz
     * @param args
     * @return
     */
    public abstract <T> int delete(Class<T> clazz,Map<String,Object> args);

    /**
     * 以自定义条件的方式删除，参数中的key为实体属性的名字，而非数据库字段名称
     * @param clazz
     * @param args
     * @return
     */
    public abstract <T> int deleteByCW(Class<T> clazz,Map<String,Object> args);

    public abstract <T> T findByPk(Class<T> requiredType, Map<String, Object> args);

    /**
     * 获取实体列表,args中的key支持运算符及逻辑符,完整格式:attributeName$运算符如>$逻辑运算符$
     * @param requiredType
     * @param args
     * @param orders
     * @param <T>
     * @return
     */
    public abstract <T> List<T> queryForList(Class<T> requiredType,
                                 Map<String, Object> args, Map<String, String> orders);

    public abstract <T> PagedData<List<T>> queryForPaging(Class<T> requiredType, int pageIndex,
                                            int pageSize, Map<String, Object> args, Map<String, String> orders);

    /**
     * 更新数据，数据由map指定，map中的key为实体属性名称
     * @param clazz
     * @param updatedData
     * @return
     */
    public abstract <T> int update(Class<T> clazz, Map<String, Object> updatedData);

    /**
     * 更新实体
     * @param t
     * @param <T>
     * @return -1重复;0:没有更新;>=1受影响的行数
     */
    public abstract <T> int update(T t);

    /**
     * 更新数据，条件自定义，由where指定
     * 更新数据及where中的key全为实体属性名称
     * @param clazz
     * @param updatedData
     * @param where
     * @return
     */
    public abstract <T> int update(Class<T> clazz, Map<String, Object> updatedData,
                          Map<String, Object> where);

    public abstract <T> int[] updateBatch(Class<T> clazz,List<T> list);

    public void withTransactionalJdbcTemplate(TransactionalJdbcTemplateHandler handler){
        TransactionalJdbcTemplate tjt = null;
        try{
            tjt = new TransactionalJdbcTemplate(getDataSource(),true);
            boolean b = handler.doHandler(tjt);
            if(b){
                tjt.commit();
            }else{
                tjt.rollback();
            }
        }catch (Exception e){
            if(tjt != null){
                tjt.rollback();
            }
            throw new RuntimeException(e);
        }finally {
            if(tjt != null){
                tjt.close();
            }
        }
    }

    public <T> T withQueryJdbcTemplate(QueryJdbcTemplateHandler<T> handler){
        QueryJdbcTemplate qjt = null;
        try{
            qjt = new QueryJdbcTemplate(getDataSource());
            return handler.doHandler(qjt);
        }finally {
            if(qjt != null){
                qjt.close();
            }
        }
    }

    public TwoTuple<String,Object[]> getCorrectGetPagingSql(String sql,int pageIndex,int pageSize,Object[] args){
        if(pageIndex<=0){
            pageIndex = 1;
        }
        if(pageSize<=0){
            pageSize = DEFAULT_PAGE_SIZE;
        }
        Object[] _args = new Object[args.length+2];
        int i;
        for(i=0;i<args.length;i++){
            _args[i] = args[i];
        }
        String pagingSql = null;
        DatabaseType dbType = JdbcPlatform.getDatabaseType(dataSource);
        if(dbType.equals(DatabaseType.MYSQL)){
            //mysql数据库
            _args[i++] = (pageIndex-1)*pageSize;
            _args[i] = pageSize;
            pagingSql = String.format(JdbcTemplate.MYSQL_PAGING_TEMPLATE,sql);
        }else if(dbType.equals(DatabaseType.MSSQL)){
            pagingSql = String.format(JdbcTemplate.MSSQL_PAGING_TEMPLATE,sql);
            _args[i++] = (pageIndex-1)*pageSize;
            _args[i] = pageSize;
        }else if(dbType.equals(DatabaseType.ORACLE)){
            pagingSql = String.format(JdbcTemplate.ORACLE_PAGING_TEMPLATE,sql);
            _args[i++] = (pageIndex-1)*pageSize+1;
            _args[i] = pageSize;
        }
        return New.tuple(pagingSql,_args);
    }
}
